#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include <asm-generic/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "parse.h"
#include "logger.h"
#include "response.h"

#define BUF_SIZE 4096
#define MAX_HEADER_SIZE 8192
#define CONTENT_TYPE "Content-Type: text/html; charset=UTF-8\r\n"
#define SERVER_INFO "Server: LisoServer/1.0\r\n"

// 定义 HTTP 错误响应常量
const char *RESPONSE_200 = "HTTP/1.1 200 OK\r\n";
const char *RESPONSE_400 = "HTTP/1.1 400 Bad request\r\n\r\n";
const char *RESPONSE_404 = "HTTP/1.1 404 Not Found\r\n\r\n";
const char *RESPONSE_500 = "HTTP/1.1 500 Internal Server Error\r\n\r\n";
const char *RESPONSE_501 = "HTTP/1.1 501 Not Implemented\r\n\r\n";
const char *RESPONSE_505 = "HTTP/1.1 505 HTTP Version not supported\r\n\r\n";

// 重新封装
int encapsulate(Request *request, char *response, char *body) {
    if (request == NULL) {
        return 0;
    }
    // 请求行
    sprintf(response, "%s %s %s\r\n", request->http_method, request->http_uri, request->http_version);
    // 请求头
    int i = 0;
    for(i = 0; i < request->header_count; i++) {
        strcat(response, request->headers[i].header_name);
        strcat(response, ": ");
        strcat(response, request->headers[i].header_value);
        strcat(response, "\r\n");
    }
    // 请求体
    if (body != NULL && strlen(body) > 0) {
        strcat(response, "\r\n");
        strcat(response, body);
        strcat(response, "\r\n");
    }
    // 结束
    strcat(response, "\r\n");
    return 1;//成功
}

int get_connection_type(Request *request){
    int keep_alive = 1;
    char *connection_header = NULL;
    int i = 0;
    for (i = 0; i < request->header_count; i++) {
        if (strcmp(request->headers[i].header_name, "Connection") == 0) {
            connection_header = request->headers[i].header_value;
            break;
        }
    }
    if (connection_header != NULL && strcmp(connection_header, "close") == 0) {
        keep_alive = 0;
    }
    return keep_alive;
}

// 获取请求头的值
char *get_header_value(Request *request, const char *header_name) {
    int i = 0;
    for (i = 0; i < request->header_count; i++) {
        if (strcmp(request->headers[i].header_name, header_name) == 0) {
            return request->headers[i].header_value;
        }
    }
    return "";
}

// 获取 CGI 脚本的名称
char *get_script_name(const char *uri) {
    char *last_slash = strrchr(uri, '/');
    if (last_slash != NULL) {
        return last_slash + 1;
    }
    return (char *)uri;
}

// 处理 GET 和 HEAD 请求
int handle_get_head(Request *request, char *response, size_t response_size) {
    if (response == NULL || request == NULL) {
        return 0; // 失败
    }
    size_t offset = 0;

    // 状态行
    offset += snprintf(response + offset, response_size - offset, "%s", RESPONSE_200);

    // 服务器信息
    offset += strncat(response + offset, SERVER_INFO, response_size - 1 - offset) - (response + offset);

    // 连接类型
    int keep_alive = get_connection_type(request);
    
    if (keep_alive) {
        offset += strncat(response + offset, "Connection: keep-alive\r\n", response_size - 1 - offset) - (response + offset);
    } else {
        offset += strncat(response + offset, "Connection: close\r\n", response_size - 1 - offset) - (response + offset);
    }

    char file_path[BUF_SIZE];
    if (strcmp(request->http_uri, "/") == 0) {
        // 请求默认文件
        snprintf(file_path, sizeof(file_path), "./static_site/index.html");
    } else {
        // 构建请求文件的路径
        snprintf(file_path, sizeof(file_path), "./static_site%s", request->http_uri);
    }

    // 打开文件失败时记录错误日志
    FILE *file = fopen(file_path, "r");
    if (file == NULL) {
        if (errno == ENOENT) {
            // 文件不存在，返回 404
            perror("Failed to open file: File not found");
            log_error("Failed to open file: File not found", errno); // 已有日志记录
            strncpy(response, RESPONSE_404, response_size);
        } else {
            // 其他错误，例如权限问题，返回 500 或 403
            perror("Failed to open file: Other error");
            log_error("Failed to open file: Other error", errno); // 已有日志记录
            strncpy(response, RESPONSE_500, response_size); 
        }
        return 1;
    }

    size_t bytes_read = 0;
    char file_content[BUF_SIZE * 2] = {0};

    bytes_read = fread(file_content, 1, sizeof(file_content) - 1, file);
    if (ferror(file)) {
        // 读取文件时发生 IO 错误，输出错误信息并返回 500 错误响应
        perror("Failed to read file");
        log_error("Failed to read file", errno); // 添加日志记录
        fclose(file);
        strncpy(response, RESPONSE_500, response_size);
        return 0;
    }

    fclose(file);
    file_content[bytes_read] = '\0';

    // 添加 Content-Type 头
    offset += strncat(response + offset, CONTENT_TYPE, response_size - 1 - offset) - (response + offset);

    // 计算 Content-Length 并添加到响应头
    char content_length_header[100];
    snprintf(content_length_header, sizeof(content_length_header), "Content-Length: %zu\r\n", bytes_read);
    offset += strncat(response + offset, content_length_header, response_size - 1 - offset) - (response + offset);

    // 空行分隔头和正文
    offset += strncat(response + offset, "\r\n", response_size - 1 - offset) - (response + offset);

    if (strcmp(request->http_method, "GET") == 0) {
        // 添加文件内容到响应
        offset += strncat(response + offset, file_content, response_size - 1 - offset) - (response + offset);
    } 

    return 1; // 返回成功
}

// 设置 CGI 环境变量
void set_cgi_environment(Request *request, const struct sockaddr_in *cli_addr, int server_port) {
    char content_length_str[20];
    snprintf(content_length_str, sizeof(content_length_str), "%d", atoi(get_header_value(request, "Content-Length")));
    setenv("CONTENT_LENGTH", content_length_str, 1);
    setenv("CONTENT_TYPE", get_header_value(request, "Content-Type"), 1);
    setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);

    char *path_info = strchr(request->http_uri, '/');
    if (path_info != NULL) {
        setenv("PATH_INFO", path_info, 1);
    }

    char *query_string = strchr(request->http_uri, '?');
    if (query_string != NULL) {
        setenv("QUERY_STRING", query_string + 1, 1);
    }

    setenv("REMOTE_ADDR", inet_ntoa(cli_addr->sin_addr), 1);
    setenv("REQUEST_METHOD", request->http_method, 1);
    setenv("REQUEST_URI", request->http_uri, 1);
    setenv("SCRIPT_NAME", get_script_name(request->http_uri), 1);

    char server_port_str[20];
    snprintf(server_port_str, sizeof(server_port_str), "%d", server_port);
    setenv("SERVER_PORT", server_port_str, 1);
    setenv("SERVER_PROTOCOL", "HTTP/1.1", 1);
    setenv("SERVER_SOFTWARE", "Liso/1.0", 1);

    setenv("HTTP_ACCEPT", get_header_value(request, "Accept"), 1);
    setenv("HTTP_REFERER", get_header_value(request, "Referer"), 1);
    setenv("HTTP_ACCEPT_ENCODING", get_header_value(request, "Accept-Encoding"), 1);
    setenv("HTTP_ACCEPT_LANGUAGE", get_header_value(request, "Accept-Language"), 1);
    setenv("HTTP_ACCEPT_CHARSET", get_header_value(request, "Accept-Charset"), 1);
    setenv("HTTP_HOST", get_header_value(request, "Host"), 1);
    setenv("HTTP_COOKIE", get_header_value(request, "Cookie"), 1);
    setenv("HTTP_USER_AGENT", get_header_value(request, "User-Agent"), 1);
    setenv("HTTP_CONNECTION", get_header_value(request, "Connection"), 1);
}

// 封装处理子进程退出状态的函数
int handle_child_exit_status(int status, Request *request, char *response, size_t response_size, int pipefd[2]) {
    // 输出子进程退出状态信息
    if (WIFEXITED(status)) {
        int exit_status = WEXITSTATUS(status);
        printf("子进程正常退出，退出状态码: %d\n", exit_status);
        if (exit_status == 0) {
            // 读取 CGI 程序的输出  
            char cgi_output[BUF_SIZE * 2];
            ssize_t bytes_read = read(pipefd[0], cgi_output, response_size);
            if (bytes_read < 0) {
                perror("Read failed");
                strncpy(response, RESPONSE_500, response_size);
                close(pipefd[0]);
                return 0;
            }
            cgi_output[bytes_read] = '\0';
            strncpy(response, RESPONSE_200, response_size);
            strncat(response, cgi_output, response_size);
            strncat(response, "\r\n", response_size);
            close(pipefd[0]);
            return 1;
        } else {
            // CGI 进程以非零状态退出
            printf("Script Name: ./cgi/%s\n", get_script_name(request->http_uri));
            perror("CGI process failed");
            strncpy(response, RESPONSE_500, response_size);
            close(pipefd[0]);
            return 0;
        }
    } else if (WIFSIGNALED(status)) {
        // 子进程因信号终止
        int term_signal = WTERMSIG(status);
        printf("子进程因信号 %d 终止\n", term_signal);
        strncpy(response, RESPONSE_500, response_size);
        close(pipefd[0]);
        return 0;
    } else if (WIFSTOPPED(status)) {
        // 子进程被暂停
        int stop_signal = WSTOPSIG(status);
        printf("子进程被信号 %d 暂停\n", stop_signal);
        strncpy(response, RESPONSE_500, response_size);
        close(pipefd[0]);
        return 0;
    }
    return 0;
}

// 处理 CGI 请求
int handle_cgi(Request *request, const struct sockaddr_in *cli_addr, char *response, size_t response_size, int server_port, char *body) {
    int pipefd[2];
    if (pipe(pipefd) < 0) {
        perror("Pipe failed");
        strncpy(response, RESPONSE_500, response_size);
        return 0;
    }
    pid_t pid = fork();
    if (pid < 0) {
        perror("Fork failed");
        strncpy(response, RESPONSE_500, response_size);
        return 0;
    } else if (pid == 0) {
        // 子进程
        set_cgi_environment(request, cli_addr, server_port);
        close(pipefd[0]);
        // 重定向标准输出到管道
        if (dup2(pipefd[1], STDOUT_FILENO) < 0) {
            perror("Dup2 failed");
            exit(EXIT_FAILURE);
        }

        if(body != NULL){
            // 打开 ./tmp 文件，清空内容并写入请求体
            int tmp_fd = open("./tmp", O_WRONLY | O_CREAT | O_TRUNC, 0644);
            if (tmp_fd < 0) {
                perror("Open ./tmp failed");
                exit(EXIT_FAILURE);
            }

            // 写入 body 到 ./tmp 文件
            if (write(tmp_fd, body, strlen(body)) < 0) {
                perror("Write failed");
                close(tmp_fd);
                exit(EXIT_FAILURE);
            }
            close(tmp_fd);

            // 重新打开 ./tmp 文件用于重定向标准输入
            tmp_fd = open("./tmp", O_RDONLY);
            if (tmp_fd < 0) {
                perror("Reopen ./tmp failed");
                exit(EXIT_FAILURE);
            }

            // 重定向标准输入到 ./tmp 文件
            if (dup2(tmp_fd, STDIN_FILENO) < 0) {
                perror("Dup2 failed");
                close(tmp_fd);
                exit(EXIT_FAILURE);
            }
            close(tmp_fd);
        }

        // 执行 CGI 程序
        char script_path[BUF_SIZE];
        snprintf(script_path, sizeof(script_path), "./cgi/%s", get_script_name(request->http_uri));
        execlp(script_path, script_path, (char *)NULL);

        // 如果 execlp 失败
        perror("Exec failed");
        exit(EXIT_FAILURE);
    } else {
        // 父进程
        int status;
        // 关闭写端，因为父进程只需要从管道读取数据
        close(pipefd[1]); 
        waitpid(pid, &status, 0);

        // 调用封装的函数处理子进程退出状态
        return handle_child_exit_status(status, request, response, response_size, pipefd);
    }
}

// 处理 POST 请求
int handle_post(Request *request, const struct sockaddr_in *cli_addr, char *response, size_t response_size, int server_port, char *body) {
    if (strstr(request->http_uri, "/cgi/") != NULL) {
        // 调用 handle_cgi 函数处理 POST 请求
        if (handle_cgi(request, cli_addr, response, response_size, server_port, body)) {
            return 1;
        } else {
            // 记录错误日志
            fprintf(stderr, "Failed to handle POST CGI request1.\n");
            strncpy(response, RESPONSE_500, response_size);
            return 0;
        }
    } else {
        // 处理普通 POST 请求
        encapsulate(request, response, body);
        return 1;
    }
}

// 统一的设置响应函数
int set_response(Request *request, const struct sockaddr_in *cli_addr, char *response, size_t response_size, int server_port, char *body) {
    // 服务器响应
    const char *response_str = NULL;
    int status = 200;
    // 检查接收到的HTTP请求格式是否正确
    if (request == NULL) {
        // 如果格式不正确，返回400错误响应
        response_str = RESPONSE_400;
        status = 400;
    } else {
        // 检查 Connection头
        char *connection_header = NULL;
        int i = 0;
        for (i = 0; i < request->header_count; i++) {
            if (strcmp(request->headers[i].header_name, "Connection") == 0) {
                connection_header = request->headers[i].header_value;
                break;
            }
        }

        // 检查 HTTP 版本
        if (strcmp(request->http_version, "HTTP/1.1") != 0) {
            printf("Unsupported HTTP version: %s\n", request->http_version);
            response_str = RESPONSE_505;
            status = 505;
        } else {
            // 解析请求方法
            const char *method = request->http_method;
            if (method == NULL || strlen(method) == 0) {
                // 若请求方法为空，返回 400
                response_str = RESPONSE_400;
                status = 400;
            } else {
                if (strstr(request->http_uri, "/cgi/") != NULL) {
                    // 处理 CGI 请求
                    if (handle_cgi(request, cli_addr, response, response_size, server_port, body)) {
                        response_str = response;
                    } else {
                        // 记录错误日志
                        fprintf(stderr, "Failed to handle CGI request.\n");
                        response_str = RESPONSE_500;
                        status = 500;
                    }
                } else if (strcmp(method, "GET") == 0 || strcmp(method, "HEAD") == 0) {
                    if (handle_get_head(request, response, response_size)) {
                        response_str = response;
                    } else {
                        // 记录错误日志
                        fprintf(stderr, "Failed to handle GET/HEAD request.\n");
                        response_str = RESPONSE_400;
                        status = 400;
                    }
                } else if (strcmp(method, "POST") == 0) {
                    if (handle_post(request, cli_addr, response, response_size, server_port, body)) {
                        response_str = response;
                    } else {
                        // 记录错误日志
                        fprintf(stderr, "Failed to handle POST request.\n");
                        response_str = RESPONSE_400;
                        status = 400;
                    }
                } else {
                    // 未实现，返回 501
                    response_str = RESPONSE_501;
                    status = 501;
                }
            }
        }
    }

    // 将响应复制到 response 中
    strncpy(response, response_str, response_size);

    // 记录访问日志
    char *method = request == NULL ? "BAD_REQUEST" : request->http_method;
    char *uri = request == NULL ? "-" : request->http_uri;
    log_access(cli_addr, method, uri, status);

    return 1;
}